#ifndef RegExp_First
#define RegExp_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Object.h"

struct re_pattern_buffer;
struct RegExRegs;

//---- RegularExp --------------------------------------------------------------
//      interface to the GNU emacs regular expression compiler,
//      refer to regex.doc for a description of its advanced features
// Examples:
//      float:  "\\(+\\|-\\)?[0-9]*\\(\\.[0-9]*\\)?"
//      int:    "\\(+\\|-\\)?[0-9]*"
//      double: "\\(+\\|-\\)?[0-9]*\\(\\.[0-9]*\\)?\\([eE]\\(+\\|-\\)?[0-9]*\\)?"
//      alpha:  "[A-Za-z]+"
//      lowercase:  "[a-z]+"
//      uppercase:  "[A-Z]+"
//      alphanum:   "[0-9A-Za-z]+"
//      identifier: "[A-Za-z_][A-Za-z0-9_]*"


const bool
	cIgnoreCase= TRUE,
	cCaseSensitive= !cIgnoreCase,
	cFastSearch= TRUE,
	cNoFastSearch= !cFastSearch;
		
class RegularExp: public Object {
	re_pattern_buffer *pb;
	char *source, *result;
	bool caseSensitive, fastSearch;
public:
	MetaDef(RegularExp);

	RegularExp(const char *pattern= 0, bool cs= cIgnoreCase, bool mode= cFastSearch);
	~RegularExp();

	void Reset(const char *pattern, bool cs= cIgnoreCase, bool mode= cFastSearch);
		// recompiles the pattern if necessary

	const char *GetExprState();
		// 0 == pattern ok, otherwise reason of failure

	int Match(const char *string, int pos= 0, int len= -1, RegExRegs *regs= 0);
		// returns length of matched pattern, starting at pos (-1= no match)

	int SearchForward(const char *string, int *nMatched, int start= 0,
						int len= -1, int range= cMaxInt, RegExRegs *regs= 0);
		// return the position of the next matching substring (-1 == no match),
		// per default the range is set up to the end of the string, nMatched
		// is set to the number of matched characters

	int SearchBackward(const char *string, int *nMatched, int start= cMaxInt,
						int len= -1, int range= cMaxInt, RegExRegs *regs= 0);
		// find next matching substring starting at pos and trying the
		// positions pos-1, pos-2 etc.

	int Match2(const char *string1, const char *string2, int len1= -1,
		int len2= -1, int pos= 0, int stopMatchAt= cMaxInt, RegExRegs *regs= 0);
		// matches the pattern as if string1 and string2 were concatented

	int SearchForward2(const char *str1, int size1, const char *str2, int size2,
				int start, int itsRange, RegExRegs *regs, int *nMatched);
		// like Match2

	int SearchBackward2(const char *str1, int size1, const char *str2, int size2,
					int start, int itsRange, RegExRegs *regs, int *nMatched);
		// like Match2

	const char *GetPattern();
		// return the pattern of this regular expression

	virtual const char *MatchWordPattern();

	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	void InspectorId(char *buf, int sz);
};

inline const char *RegularExp::GetExprState()
	{ return result; }
inline const char *RegularExp::GetPattern()
	{ return source; }

//---- RegularExp --------------------------------------------------------------

class SmartRegularExp {
	char *expr;
	RegularExp *re;
public:
	SmartRegularExp(char *e)
		{ expr= e; re= 0; }
	~SmartRegularExp()
		{ SafeDelete(re); }
	operator RegularExp* ()
		{ return re ? re : (re= new RegularExp(expr)); }
	RegularExp* operator -> ()
		{ return re ? re : (re= new RegularExp(expr)); }
};

extern SmartRegularExp gRexDouble, gRexInt;

//---- RegExRegs ---------------------------------------------------------------
//   Structure to store "register" contents data in.
//
//   Pass the address of such a structure as an argument to Match, etc.,
//   if you want this information back.
//
//   start[i] and end[i] record the string matched by \( ... \) grouping i,
//   for i from 1 to cNumReg - 1.
//   start[0] and end[0] record the entire string matched.
//   eg: Regex = "a\(b*\)c"
//       String = "abbbbc"
//       start[1]= 1, end[1]= 5
//

const int cNumRegs= 10;

struct RegExRegs {
	int start[cNumRegs];
	int end[cNumRegs];

	const char *StringAt(const char *buf, int x);
	int LengthAt(int x)
		{ return end[x] - start[x]; }
};

#endif

